#include <windows.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

// define character structure
struct character {
	const char * name;
	int HP;
	int initiative;
	int AC;
	const char * melee_atk_name;
	const char * melee_atk_verb;
	const char * melee_dmg_verb;
	int melee_atk_bonus;
	int melee_dmg_dice;
	int melee_dmg_bonus;
	const char * ranged_atk_name;
	const char * ranged_atk_verb;
	const char * ranged_dmg_verb;
	int ranged_atk_bonus;
	int ranged_dmg_dice;
	int ranged_dmg_bonus;
	int bullets;
	bool has_ranged_weapon;
	bool can_fly;
	bool is_flying;
	bool is_player;
};

// define characters
character Player = { "Player", 40, 4, 20, "fists", "punch", "bruises", 15, 3, 3, "pistol", "shoot", "pierces", 10, 10, 10, 6, true, false, false, true };
character Dragon = { "dragon", 40, 8, 20, "claws", "swipe", "cuts", 8, 10, 5, "fire breath", "attack", "burns", 10, 10, 10, 1, true, true, false, false };
character Goblin = { "goblin", 20, 4, 15, "stick", "hit", "bruises", 10, 3, 3, "sling", "shoot", "hits", 5, 3, 3, 3, true, false, false, false };
character Eagle = { "giant eagle", 40, 4, 15, "talon", "grab", "tears", 15, 3, 3, "talon", "attack", "hits", 5, 3, 3, 1, false, true, false, false };
character Kitten = { "kitten", 10, 10, 2, "paw", "hit", "bruises", 15, 3, 3, "furball", "spit", "hits", 5, 3, 3, 1, false, false, false, false };

character * attacker = &Player;
character * defender = &Dragon;
character * enemy = defender;


// functions:
int roll(int sides)
{
	return rand() % sides + 1;
}

void chooseEnemy(character *& defender)
{
	//int enemy = roll(4);
	switch (roll(4))
	{
	case 1:
		defender = &Dragon;
		break;
	case 2:
		defender = &Goblin;
		break;
	case 3:
		defender = &Eagle;
		break;
	case 4:
		defender = &Kitten;
		break;
	}
}

void changeTurn(character *& attacker, character *& defender)
{
	character * temporary = attacker;
	attacker = defender;
	defender = temporary;
}

void meleeAttack(character * attacker, character * defender)
{
	cout << endl;
	cout << "The " <<  attacker->name << " tries to " << attacker->melee_atk_verb << " the " << defender->name << " with " << attacker->melee_atk_name << "..." << endl;
	if (defender->is_flying)
	{
		cout << "the " << attacker->melee_atk_verb << " fails to reach the flying " << defender->name << endl;
	}
	else if (roll(20) + attacker->melee_atk_bonus >= defender->AC)
	{
		cout << "the " << attacker->melee_atk_verb << " penetrates the " << defender->name << "'s armour and " << attacker->melee_dmg_verb << " the muscle." << endl;
		defender->HP -= roll(attacker->melee_dmg_dice) + attacker->melee_dmg_bonus;
	}
	else
	{
		cout << "the " << attacker->melee_atk_verb << " scratches the " << defender->name << " but does no damage." << endl;
	}
	cout << endl;
}

void rangedAttack(character * attacker, character * defender)
{
	cout << endl;
	cout << attacker->name << " " << attacker->ranged_atk_verb << "s at the " << defender->name << " with a " << attacker->ranged_atk_name << "..." << endl;
	if (roll(20) + attacker->ranged_atk_bonus >= defender->AC)
	{
		cout << attacker->name << "'s attack " << attacker->ranged_dmg_verb << " the "<< defender->name << "." << endl;
		defender->HP -= roll(attacker->ranged_dmg_dice) + attacker->ranged_dmg_bonus;
	}
	else
	{
		cout << attacker->name << "'s attack bounces off the " << defender->name << "." << endl;
	}
	attacker->bullets--;
	cout << endl;
}

void disableInputBuffering()
{
     HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
     DWORD mode;
     GetConsoleMode(console, &mode);
     SetConsoleMode(console, mode & ~ENABLE_LINE_INPUT);
     cin >> noskipws;
}

void initializeRandomGenerator()
{
	srand((int)time(0));
}

// main program:
int main()
{
	disableInputBuffering();
	initializeRandomGenerator();

    char answer;

	bool keep_playing = true;
	while (keep_playing)
	{
		// randomize enemy
		chooseEnemy(defender);
		character * enemy = defender;
  
		cout << "A " << defender->name << "!" << endl;
		cout << endl;

		// randomize who gets first hit:
		bool player_turn = (roll(20) + Player.initiative > roll(20) + 1 + enemy->initiative);
		if (!player_turn)
		{
			changeTurn(attacker, defender);
		}

		// start combat:
		bool do_combat = true;
		while (do_combat)
		{
			//player's turn:
			if (attacker->is_player)
			{
				answer = '?';
				while (answer == '?')
				{
					cout << "Will you:" << endl;
					cout << "[m] attack the " << defender->name << " with your " << attacker->melee_atk_name << "," << endl;
					if (attacker->bullets > 0)
					{
						cout << "[s] " << attacker->ranged_atk_verb << " at the " << defender->name  << " with your " << attacker->ranged_atk_name << " (" << attacker->bullets << " bullets)," << endl;
					}
					else if (attacker->has_ranged_weapon)
					{
						cout << "[t] throw the " << attacker->ranged_atk_name << " at the " << defender->name  << endl;
					}
					cout << "[r] run away." << endl;
					cout << endl;
					cout << ">";

					cin >> answer;

					switch (answer)
					{
				
					case 's':
						if (attacker->bullets > 0)
						{
							rangedAttack(attacker, defender);
						}
						else
						{
							cout << endl;
							cout << "You are out of ammo!" << endl;
							cout << endl;
							answer = '?';
						}
						break;

					case 't':
						if (attacker->has_ranged_weapon)
						{
							cout << endl;
							cout << attacker->name << " throws the " << attacker->ranged_atk_name << " at the " << defender->name << "..." << endl;
							attacker->has_ranged_weapon = false;
							if (roll(20) + attacker->ranged_atk_bonus >= defender->AC)
							{
								cout << "The " << attacker->ranged_atk_name << " hits the " << defender->name << " in the eye," << endl;
								cout << "the " << defender->name << " is now half-blind and twice as angry." << endl;
								defender->HP -= roll(attacker->ranged_dmg_dice) + attacker->ranged_dmg_bonus;
								defender->melee_atk_bonus -= defender->melee_atk_bonus/2;
								defender->melee_dmg_bonus *= 2;
							}
							else
							{
								cout << attacker->name << " misses the " << defender->name << "." << endl;
							}
							cout << endl;
						}
						break;
				
					case 'm':
						meleeAttack(attacker, defender);
						break;

					case 'r':
						cout << endl;
						cout << "The " << defender->name << " tries to " << defender->melee_atk_verb << attacker->name << " as he's fleeing..." << endl;
						if (roll(20) + defender->melee_atk_bonus + 2 >= attacker->AC - 5)
						{
							cout << "the " << defender->melee_atk_verb << " penetrates " << attacker->name << "'s armour and " << defender->melee_dmg_verb << " the muscle." << endl;
							attacker->HP -= roll(defender->melee_dmg_dice) + defender->melee_dmg_bonus;
						}
						else
						{
							cout << "the hit scratches " << attacker->name << "'s armour but does no damage." << endl;
						}
						cout << endl;
						do_combat = false;
						break;
				
					default:
						cout << endl;
						cout << "I didn't understand that." << endl;
						cout << endl;
						answer = '?';
						break;
					}
				}
			}
			else
			{ // enemy's turn
			
				if  ((attacker->can_fly && !(attacker->is_flying)) && (roll(20) >= 16))
				{
					cout << endl;
					cout << "The " <<  attacker->name << " flaps it's wings and rises into air." << endl;
					attacker->is_flying = true;
					cout << endl;
				}
				else if ((attacker->is_flying) && (roll(20) >= 12))
				{
					cout << endl;
					cout << "The " <<  attacker->name << " circles in the air above the " << defender->name << " ." << endl;
					cout << endl;
				}
				else if (attacker->is_flying)
				{
					cout << endl;
					cout << "The " <<  attacker->name << " lands next to the " << defender->name << ", sending dust and rocks flying around." << endl;
					attacker->is_flying = false;
					cout << endl;
				}
				else if (!(attacker->is_flying))
				{
					if ((attacker->bullets > 0) && (roll(2) >= 2))
					{
						rangedAttack(attacker, defender);
					}
					else
					{
						meleeAttack(attacker, defender);
					}
				}
		
			} // end enemy's turn

			// swap turns
			changeTurn(attacker, defender);

			// end combat if either one ise dead
			if (attacker->HP < 1 || defender->HP < 1)
			{
				do_combat = false;
			}
		}

		// check who won
		if (Player.HP < 1)
		{
			cout << endl;
			cout << "You died!" << endl;
		}
		else if (enemy->HP < 1)
		{
			cout << endl;
			cout << "You defeated the " << enemy->name << "!" << endl;
		} 
		else
		{
			cout << endl;
			cout << "You live to fight another day..." << endl;
		}

		cout << endl;
		cout << "Fight again (y/n)?" << endl;
		cin >> answer; // wait for keypress to end
		if (answer == 'y')
		{
			keep_playing = true;
			attacker = &Player;
			cout << endl << endl;
		}
		else {
			keep_playing = false;
		}
	}
	return 0;
}
